package com.hibase.core.dingding.util;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.system.SystemUtil;
import com.alibaba.fastjson.JSON;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;
import com.dingtalk.api.request.OapiRobotSendRequest;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
import com.dingtalk.api.response.OapiRobotSendResponse;
import com.hibase.common.entity.User;
import com.hibase.common.util.UserContext;
import com.hibase.core.dingding.entity.DdResponse;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Optional;

/**
 * @author ChrisCui
 * @date 2019/06/24
 */
@Slf4j
@Component
public class DingDingUtil {

    private static String CORPID = "dingbkeqpvhe8th2bsxo"; // 企业Id
    private static String CORPSECRET = "_U8gVCjy6Yp7QsSaR1TClZe-b-KqC0HhFeQXcZmz-EcTy_YosG62h42Ti8fM4401"; // 企业应用的凭证密钥
    public static Long AGENTID = 258756589L; // 自动分配微应用的ID
    private static String USERID = "430523199405156613,420607199503221216,430621198810121834";

    public static final String MARKDOWN = "markdown";
    public static final String TEXT = "text";
    public static final String LINK = "link";
    public static final String BASE_URL = "https://oapi.dingtalk.com/robot/send?access_token=";

    private static Boolean isEnable = Boolean.TRUE;
    private static String ddMessageToken;

    private static String appName;

    @Value("${spring.application.name}")
    public void setAppName(String appName) {
        DingDingUtil.appName = appName;
    }

    @Value("${hibase.dingding.enable}")
    public void setIsEnable(Boolean isEnable) {
        DingDingUtil.isEnable = isEnable;
    }

    @Value("${hibase.dingding.ddMessageToken:efa89232854b4277b2c8bafb388988e4f59605f439392f95140be6b83964483b}")
    public void setDdMessageToken(String ddMessageToken) {
        DingDingUtil.ddMessageToken = ddMessageToken;
    }

    /**
     * @param corpid     企业Id
     * @param corpsecret 企业应用的凭证密钥
     * @Description:获得token
     * @Method:getToken
     * @Authod:ChrisCui
     * @Date:2019/6/24
     */
    private static String getToken(String corpid, String corpsecret) {
        try {
            DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
            OapiGettokenRequest request = new OapiGettokenRequest();
            request.setAppkey(corpid);
            request.setAppsecret(corpsecret);
            request.setHttpMethod("GET");
            OapiGettokenResponse response = client.execute(request);
            return response.getAccessToken();
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param agentId    微应用的ID
     * @param corpid     微应用的corpid
     * @param corpsecret 微应用的corpsecret
     * @param userId     接收者的用户userid列表 多个用半角逗号隔开
     * @param msgcontent 消息内容
     * @Description:发送工作通知消息
     * @Method:sendDDMessage
     * @Authod:ChrisCui
     * @Date:2019/6/24
     */
    public static String sendDDMessage(Long agentId, String corpid, String corpsecret, String userId, String msgcontent) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setUseridList(userId);
        request.setAgentId(agentId);
        request.setToAllUser(false);

        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
        msg.setMsgtype("text");
        msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
        msg.getText().setContent(msgcontent);
        request.setMsg(msg);
        try {
            OapiMessageCorpconversationAsyncsendV2Response response = client.execute(request, getToken(corpid, corpsecret));
            return response.getErrcode().toString();
        } catch (ApiException e) {
            e.printStackTrace();
        }

        return null;
    }


    public static Boolean sendDDROBOTMessage(String accessToken, String secret, String msgType, String title, String msgContent,
                                             Boolean isAtAll) {
        if (!isEnable) {
            return isEnable;
        }
        String url = BASE_URL.concat(accessToken);
        if (StrUtil.isNotBlank(secret)) {
            Long timestamp = System.currentTimeMillis();
            String sign = getSign(timestamp, secret);
            url = url.concat("&timestamp=").concat(timestamp.toString()).concat("&sign=").concat(sign);
        }
        // step 1. 自定义机器人基本参数设置
        DingTalkClient client = new DefaultDingTalkClient(url);
        OapiRobotSendRequest request = new OapiRobotSendRequest();
        // step 2. 判断消息类型  text | link | markdown
        if (TEXT.equals(msgType)) {
            request.setMsgtype(TEXT);
            OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
            text.setContent(msgContent);
            request.setText(text);
            if (isAtAll) {
                OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
                at.setIsAtAll("true");
                request.setAt(at);
            }
            // 下面是@ 成员功能
            /*OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
            at.setAtMobiles(Collections.singletonList("18482132737"));
            request.setAt(at);*/
        } else if (LINK.equals(msgType)) {
            request.setMsgtype(LINK);
            OapiRobotSendRequest.Link link = new OapiRobotSendRequest.Link();
            link.setMessageUrl("https://www.hichain.com/");
            link.setPicUrl("https://www.hichain.com/static/hichainLogo.af6428d0.png");
            link.setTitle(title);
            link.setText(msgContent);
            request.setLink(link);
            if (isAtAll) {
                OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
                at.setIsAtAll("true");
                request.setAt(at);
            }
        } else if (MARKDOWN.equals(msgType)) {
            request.setMsgtype(MARKDOWN);
            OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown();
            markdown.setTitle(title);
            markdown.setText(msgContent);
            request.setMarkdown(markdown);
            if (isAtAll) {
                OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
                at.setIsAtAll("true");
                request.setAt(at);
            }
        } else {
            return false;
        }
        try {
            // step 3. 消息发送
            log.info("【钉钉-消息】 发送钉钉消息: {}", JSON.toJSONString(request));
            OapiRobotSendResponse response = client.execute(request);
            return response.isSuccess();
        } catch (ApiException e) {
            log.info("【钉钉-异常】 钉钉群消息发送失败 :{}", e.getErrMsg());
            e.printStackTrace();
        }
        return false;
    }

    /**
     * @param robotUrl   群机器人URL
     * @param msgcontent 消息内容
     * @Description:发送群机器人消息
     * @Method:sendDDMessage
     * @Authod:ChrisCui
     * @Date:2019/6/24
     */
    public static String sendHttpDDROBOTMessage(String robotUrl, String msgcontent) {
        String response = HttpUtil.post(robotUrl, msgcontent);
        DdResponse ddResponse = JSON.parseObject(response, DdResponse.class);
        log.info("钉钉消息调用返回：{}", response);
        return ddResponse.getErrcode();
    }

    /**
     * 获取签名
     * @param timestamp
     * @param secret
     * @return
     */
    private static String getSign(Long timestamp, String secret) {
        try {
            String stringToSign = timestamp + "\n" + secret;
            Mac mac = null;
            mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
            return URLEncoder.encode(Base64.encode(signData), "UTF-8");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args) {
//        Boolean aBoolean = sendDDROBOTMessage(null, null, "text", "text");
//        Boolean bBoolean = sendDDROBOTMessage(null, null, "link", "link");
        String msgContent = "#### excel \n" +
                "> ##### excelTest [点击通知下载](http://hfs.hichain.com/file-manager/downloadFile?appId=002&fileToken=e85cd95504b74627bdf08e605bceeb66) \n";
        String testContent = "TEST通知";
        String accessToken = "efa89232854b4277b2c8bafb388988e4f59605f439392f95140be6b83964483b";
        Boolean cBoolean = sendDDROBOTMessage(accessToken, null, TEXT, null, testContent, true);
    }

    public static Boolean sendAppMessage(String message) {
        String hostIp = NetUtil.getLocalhostStr();
        return sendAppMessage(message, hostIp);
    }

    public static Boolean sendAppMessage(String message, String ip) {
        // step 1. 构建消息结构
        String title = "【服务器通知】";
        String hostName = SystemUtil.getHostInfo().getName();
        String userName = SystemUtil.getUserInfo().getName();
        String userHome = SystemUtil.getUserInfo().getCurrentDir();
        long pid = SystemUtil.getCurrentPID();
        //String hostIp = SystemUtil.getHostInfo().getAddress();
        String active = SpringUtil.getActiveProfile();
        // step 2. 转markdown
        message = "<font color=#65c294 size=3 face=\"黑体\">".concat(message).concat("</font>");
        String markdownMsg = StrUtil.format(
                "【{}服务器通知】 \n" +
                        "* 时间 : {}\n" +
                        "* 环境 : {}\n" +
                        "* 主机 : {}\n" +
                        "* 用户 : {}\n" +
                        "* 路径 : {}\n" +
                        "* pid : {}\n" +
                        "* IP : {}\n" +
                        "*** \n" +
                        "* 消息 : **{}**", appName, DateUtil.now(), active, hostName, userName, userHome, pid, ip, message);
        // step 3. 发送到钉钉群
        String accessToken = ddMessageToken;
        return sendDDROBOTMessage(accessToken, null, MARKDOWN, title, markdownMsg, false);
    }

    public static Boolean sendExceptionMessage(String message) {
        return sendExceptionMessage(StrUtil.format("【{}异常通知】", appName), message);
    }

    public static Boolean sendExceptionMessage(String prefix, String message) {
        String hostIp = NetUtil.getLocalhostStr();
        return sendExceptionMessage(prefix, message, hostIp);
    }

    public static Boolean sendExceptionMessage(String prefix, String message, String ip) {
        if (message == null) {
            message = "";
        }
        // step 1. 构建消息结构
        String title = "【异常通知】";
        HttpServletRequest request = null;
        String uri = null;
        Optional<ServletRequestAttributes> optional = Optional.
                ofNullable((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
        if (optional.isPresent()) {
            request = optional.map(attr -> attr.getRequest()).get();
            uri = Optional.ofNullable(request)
                    .map(req -> URLUtil.getPath(req.getRequestURI()))
                    .get();
        }
        String userName;
        Optional<User> user = Optional.ofNullable(UserContext.get());
        if (user.isPresent()) {
            userName = user.map(context -> context.getLoginName())
                    .orElse(SystemUtil.getUserInfo().getName());
        } else {
            userName = SystemUtil.getUserInfo().getName();
        }
        String userHome = SystemUtil.getUserInfo().getCurrentDir();
        String hostName = SystemUtil.getHostInfo().getName();
        long pid = SystemUtil.getCurrentPID();
        //String hostIp = SystemUtil.getHostInfo().getAddress();
        String active = SpringUtil.getActiveProfile();
        // step 2. 转markdown
        message = "<font color=#FF0000 size=3 face=\"黑体\">".concat(message).concat("</font>");
        String markdownMsg;
        if (StrUtil.isNotBlank(uri)) {
            // 区分是否有请求URI
            markdownMsg = StrUtil.format(
                    prefix + " \n" +
                            "* 时间 : {}\n" +
                            "* 环境 : {}\n" +
                            "* 主机 : {}\n" +
                            "* URI : {}\n" +
                            "* 用户 : {}\n" +
                            "* 路径 : {}\n" +
                            "* pid : {}\n" +
                            "* IP : {}\n" +
                            "*** \n" +
                            "* 消息 : **{}**", DateUtil.now(), active, hostName, uri, userName, userHome, pid, ip, message);
        } else {
            markdownMsg = StrUtil.format(
                    prefix + " \n" +
                            "* 时间 : {}\n" +
                            "* 环境 : {}\n" +
                            "* 主机 : {}\n" +
                            "* 用户 : {}\n" +
                            "* 路径 : {}\n" +
                            "* pid : {}\n" +
                            "* IP : {}\n" +
                            "*** \n" +
                            "* 消息 : **{}**", DateUtil.now(), active, hostName, userName, userHome, pid, ip, message);
        }
        // step 3. 发送到钉钉群
        String accessToken = ddMessageToken;
        return sendDDROBOTMessage(accessToken, null, MARKDOWN, title, markdownMsg, true);
    }
}
